package edu.albany.csi518.sick;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedSet;
import java.util.TreeMap;

/**
 *
 * @author John M. Lien
 */
public class CalculateConfidence {

    private final DiseaseSymptom disease_symptom;
    private final TreeMap<Double, ArrayList<String>> disease_symptom_scores;
    private final HashMap<String, ArrayList<String>> reduce_symptom_disease_hashmap;
    private final TreeMap<Double, ArrayList<String>> disease_symptom_ranked_output;
    private Double max_score;

    public ArrayList<Integer> getChosenVales(String input) {;
        ArrayList<Integer> user_selection = new ArrayList();
        String[] split;

        /* Remove all non numbers */
        input = input.replaceAll("[^0-9 ]", "").replaceAll("[\\s+]", " ");
        split = input.split(" ");

        for (String tok : split) {
            try {
                user_selection.add(Integer.valueOf(tok));
            } catch (Exception e) {
                //Just junk
            }
        }

        Collections.sort(user_selection);

        return user_selection;
    }

    public void printChosenDiseases(String input) {
        boolean print_all = false;
        ArrayList<Integer> user_selection = this.getChosenVales(input);
        HashMap<String, ArrayList<String>> hashmap = this.disease_symptom.getLastQueryHashMap();
        ArrayList<String> set = new ArrayList(hashmap.keySet());
        Collections.sort(set);
        if (input.trim().equalsIgnoreCase("all")) {
            print_all = true;
        }
        for (int i = 0; i < set.size(); i++) {
            if (print_all) {
                System.out.println("\n" + (i + 1) + ")\nDisease:\t" + set.get(i));
                System.out.println("Symptoms:\t" + hashmap.get(set.get(i)));
            } else {
                if (user_selection.contains((i + 1))) {
                    System.out.println("\n" + (i + 1) + ")\nDisease:\t" + set.get(i));
                    System.out.println("Symptoms:\t" + hashmap.get(set.get(i)));
                }
            }
        }
    }

    public ArrayList<String> getChosenSymptoms(String input) {
        ArrayList<Integer> user_selection = this.getChosenVales(input);
        ArrayList<String> user_selection_string = new ArrayList();
        Iterator<Map.Entry<String, Integer>> iterator = this.disease_symptom.getLastQueryTreeMap().iterator();
        Map.Entry<String, Integer> next;
        for (int i = 1; iterator.hasNext(); i++) {
            next = (Map.Entry<String, Integer>) iterator.next();
            if (user_selection.contains(i)) {
                user_selection_string.add(next.getKey());
            }
        }
        return user_selection_string;
    }

    private void populateReducedHashMap(ArrayList<String> search_terms, ArrayList<String> additional_symptoms) {
        HashMap<String, ArrayList<String>> disease_symptom_hashmap = this.disease_symptom.getLastQueryHashMap();
        for (String key : disease_symptom_hashmap.keySet()) {
            for (String tok : additional_symptoms) {
                if (disease_symptom_hashmap.get(key).contains(tok)) {
                    if (!this.reduce_symptom_disease_hashmap.containsKey(key)) {
                        this.reduce_symptom_disease_hashmap.put(key, new ArrayList());
                        for (String term : search_terms) {
                            if (!this.reduce_symptom_disease_hashmap.get(key).contains(term)) {
                                this.reduce_symptom_disease_hashmap.get(key).add(term);
                            }
                        }
                    }
                    if (!this.reduce_symptom_disease_hashmap.get(key).contains(tok)) {
                        this.reduce_symptom_disease_hashmap.get(key).add(tok);
                    }
                }
            }
        }
        if (this.reduce_symptom_disease_hashmap.isEmpty()) {
            for (String key : disease_symptom_hashmap.keySet()) {
                this.reduce_symptom_disease_hashmap.put(key, new ArrayList());
                for (String tok : search_terms) {
                    this.reduce_symptom_disease_hashmap.get(key).add(tok);
                }
            }
        }
    }

    private void calculateDiseaseSymptomScores() {
        SortedSet<Entry<String, Integer>> map_scores = this.disease_symptom.getLastQueryFullTreeMap();
        Iterator<Map.Entry<String, Integer>> iterator;
        Map.Entry<String, Integer> element;
        HashMap<String, Double> max = new HashMap();
        double score;
        int average = 0;
        iterator = map_scores.iterator();
        while (iterator.hasNext()) {
            average += iterator.next().getValue();
        }        
        average += max.size();
        for (String key : this.reduce_symptom_disease_hashmap.keySet()) {
            score = 0;
            for (String tok : this.reduce_symptom_disease_hashmap.get(key)) {
                iterator = map_scores.iterator();
                while (iterator.hasNext()) {
                    element = iterator.next();
                    if (element.getKey().equals(tok)) {
                        if (!max.containsKey(tok)) {
                            max.put(tok, Math.log(average / element.getValue()));
                        }
                        score += Math.log(average / element.getValue());
                    }
                }
            }
            if (!this.disease_symptom_scores.containsKey(score)) {
                this.disease_symptom_scores.put(score, new ArrayList());
                this.disease_symptom_scores.get(score).add(key);
            } else {
                this.disease_symptom_scores.get(score).add(key);
            }
        }
        for (String key : max.keySet()) {
            this.max_score += max.get(key);
        }

        for (Double key : this.disease_symptom_scores.keySet()) {
            this.disease_symptom_ranked_output.put((double) (((double) ((int) (10000 * (key / this.max_score)))) / 100), this.disease_symptom_scores.get(key));
        }
    }

    public void calculateConfidence(String input) {
        ArrayList<String> additional_symptoms = this.getChosenSymptoms(input);
        ArrayList<String> search_terms = this.disease_symptom.getLastSearchTerms();
        this.resetData();
        this.populateReducedHashMap(search_terms, additional_symptoms);
        this.calculateDiseaseSymptomScores();
    }

    public void printReducedSymptomHashMap() {
        ArrayList<String> terms = new ArrayList(this.reduce_symptom_disease_hashmap.keySet());
        Collections.sort(terms);
        System.out.println("Matched Symptoms to Diseases:");
        for (String key : terms) {
            System.out.println(key + "\t" + this.reduce_symptom_disease_hashmap.get(key));
        }
    }

    public TreeMap<Double, ArrayList<String>> getCalculatedConfidenceTree(){
        return disease_symptom_ranked_output;
    }
    
    public void printCalculatedConfidence() {
        System.out.println("Resulting Diseases Listed By Percentage of Confidence:");
        for (Double key : this.disease_symptom_ranked_output.keySet()) {
            System.out.println(key + "%\t" + this.disease_symptom_ranked_output.get(key));
        }
    }

    private void resetData() {
        this.disease_symptom_scores.clear();
        this.reduce_symptom_disease_hashmap.clear();
        this.disease_symptom_ranked_output.clear();
        this.max_score = 0.0;
    }

    public CalculateConfidence(DiseaseSymptom disease_symptom) {
        this.disease_symptom = disease_symptom;
        this.reduce_symptom_disease_hashmap = new HashMap();
        this.disease_symptom_scores = new TreeMap(Collections.reverseOrder());
        this.disease_symptom_ranked_output = new TreeMap(Collections.reverseOrder());
    }
}
